// just build this file

// Usage:
// .\podw.exe  pull -f .\mirrorv2.txt docker.io/library/clickhouse
package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"

	"github.com/spf13/cobra"
)

var mirrorPrefix string
var mirrorFile string
var mirrorContent []byte

var rootCmd = &cobra.Command{
	Use:   "podw",
	Short: "Podw 是一个容器镜像拉取命令的包装工具",
	Long:  `Podw 会在拉取镜像前检查镜像是否在允许列表中，并自动添加镜像仓库前缀.`,
}

var pullCmd = &cobra.Command{
	Use:   "pull IMAGE",
	Short: "拉取镜像",
	Long:  `拉取镜像命令会检查镜像是否在允许列表中，并自动添加镜像仓库前缀.`,
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		image := args[0]

		// 读取镜像列表文件
		mirrorContent, err := readMirrorFile()
		if err != nil {
			fmt.Printf("读取镜像列表失败: %v\n", err)
			return
		}

		// 检查镜像是否在允许列表中
		if !imageExistsInMirror(image, mirrorContent) {
			fmt.Printf("镜像 %s 不在镜像列表中，不允许拉取\n", image)
			return
		}

		// 构造新的镜像名称
		newImage := fmt.Sprintf("%s/%s", mirrorPrefix, image)

		// 验证镜像名称格式
		if !isValidImageName(newImage) {
			fmt.Printf("镜像名称格式不正确: %s\n", newImage)
			return
		}

		// 检测可用的容器运行时
		containerRuntime, err := detectContainerRuntime()
		if err != nil {
			fmt.Printf("未检测到可用的容器运行时: %v\n", err)
			return
		}

		// 执行拉取命令
		fmt.Printf("正在使用 %s 拉取镜像 %s...\n", containerRuntime, newImage)
		cmdOutput, err := exec.Command(containerRuntime, "pull", newImage).CombinedOutput()
		if err != nil {
			fmt.Printf("拉取镜像失败: %s\n", string(cmdOutput))
			return
		}

		fmt.Printf("拉取镜像成功: %s\n", newImage)
	},
}

func init() {
	// 添加 --prefix 标志，默认值为 m.daocloud.io
	pullCmd.Flags().StringVarP(&mirrorPrefix, "prefix", "p", "m.daocloud.io", "设置镜像仓库前缀")
	// 添加 --mirror-file 标志，允许指定自定义镜像列表文件
	pullCmd.Flags().StringVarP(&mirrorFile, "mirror-file", "f", "", "指定自定义镜像列表文件")
	rootCmd.AddCommand(pullCmd)

	// 初始化时尝试读取当前目录下的mirror.txt
	initMirrorContent()
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// 初始化镜像内容
func initMirrorContent() {
	// 检查当前目录下是否存在mirror.txt
	currentDir, err := os.Getwd()
	if err != nil {
		fmt.Printf("警告: 获取当前目录失败: %v\n", err)
		return
	}

	mirrorPath := filepath.Join(currentDir, "mirror.txt")
	if _, err := os.Stat(mirrorPath); err == nil {
		// 文件存在，读取内容
		content, err := os.ReadFile(mirrorPath)
		if err != nil {
			fmt.Printf("警告: 读取镜像列表文件失败: %v\n", err)
			return
		}

		mirrorContent = content
		fmt.Println("已加载当前目录下的mirror.txt")
		return
	}
}

// 读取镜像列表文件内容
func readMirrorFile() ([]byte, error) {
	if mirrorFile != "" {
		// 读取用户指定的文件
		return os.ReadFile(mirrorFile)
	}

	// 使用初始化时加载的内容
	if mirrorContent != nil {
		return mirrorContent, nil
	}

	return nil, fmt.Errorf("未找到可用的镜像列表")
}

// 检查镜像是否存在于镜像列表中
func imageExistsInMirror(image string, content []byte) bool {
	lines := bytes.Split(content, []byte("\n"))
	for _, line := range lines {
		line = bytes.TrimSpace(line)
		if bytes.Equal(line, []byte(image)) {
			return true
		}
	}
	return false
}

// 使用正则表达式验证镜像名称格式
func isValidImageName(image string) bool {
	// 常见的 Docker 镜像名称格式
	pattern := `^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:[0-9]+)?/)?([a-zA-Z0-9-._]+/)*[a-zA-Z0-9-._]+$`
	matched, err := regexp.MatchString(pattern, image)
	if err != nil {
		return false
	}
	return matched
}

// 检测系统中可用的容器运行时
func detectContainerRuntime() (string, error) {
	runtimes := []string{"podman", "docker"}

	for _, runtime := range runtimes {
		_, err := exec.LookPath(runtime)
		if err == nil {
			// 验证命令是否能正常执行
			if _, err := exec.Command(runtime, "version").CombinedOutput(); err == nil {
				return runtime, nil
			}
		}
	}

	return "", fmt.Errorf("未找到可用的容器运行时，请确保安装了 podman 或 docker")
}
